﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using Fusion;

namespace Fusion
{
    public class Prop : Entity
    {
        #region Attributes

		public Solid solid;
		public List<Entity> collisionLayer;

		// Physics
		public Vector2 velocity;
		public float torque;

		public Vector2 gravity = new Vector2( 0, 1024 );
		public Vector2 terminal = new Vector2( 1024, 1024 );

		// Surroundings
		public bool onFloor;
		public bool onRoof;
		public bool onLeft;
		public bool onRight;
        
        #endregion
		

        #region Constructors

        /// <summary> Basic Constructor </summary>
        public Prop()
		{
        }

		/// <summary> Copies an entity </summary>
		/// <param name="from">Entity to copy from</param>
		/// <returns>this</returns>
		public override Entity Copy( Entity original )
		{
			base.Copy( original );

			if( original is Prop )
			{
				Prop op = original as Prop;

				if( op.solid != null )
					solid = op.solid.Clone();

				velocity = op.velocity;
				torque = op.torque;
				terminal = op.terminal;
				gravity = op.gravity;
			}
			return this;
		}

        #endregion
		

        #region Methods

        /// <summary> Update method </summary>
        public override void Update()
		{
			float period = Engine.period;
			// Gravity
			velocity += gravity * period;

			// Clamp
			velocity = Vector2.Clamp( velocity, -terminal, terminal );
			torque = MathHelper.Clamp( torque, -1, 1 );

			// Movement
			angle += torque * period;

			// World clamp

			if( collisionLayer != null )
			{
				Entity col;
				Vector2 projection = Vector2.Zero;
				Vector2 xmovement = velocity * period; xmovement.Y = 0;
				Vector2 ymovement = velocity * period; ymovement.X = 0;
				onFloor = onRoof = onLeft = onRight = false;

				col = TestMovement( xmovement, ref projection, collisionLayer );
				if( col != null )
				{
					if( projection.X < 0 ) onRight = true;
					if( projection.X > 0 ) onLeft = true;
				}
				position += xmovement + projection;

				col = TestMovement( ymovement, ref projection, collisionLayer );
				if( col != null )
				{
					if( projection.Y < 0 ) onFloor = true;
					if( projection.Y > 0 ) onRoof = true;
				}
				position += ymovement + projection;
			}
			else
				position += velocity * period;

			
			// Cut velocity
			if( onFloor == true && velocity.Y > 0 ) velocity.Y = 0;
			if( onRoof == true && velocity.Y < 0 ) velocity.Y = 0;
			if( onRight == true && velocity.X > 0 ) velocity.X = 0;
			if( onLeft == true && velocity.X < 0 ) velocity.X = 0;

            base.Update();
        }

        /// <summary> Tests intersection with a point </summary>
        public override bool Intersect( Vector2 point, ref Vector2 projection )
        {
			if( solid == null )
				return false;

            return solid.Intersect( point, ref projection );
        }

        /// <summary> Tests intersection with a line </summary>
        public override bool Intersect( Vector2 from, Vector2 to, ref Vector2 point, ref float slice )
		{
			if( solid == null )
				return false;

			return solid.Intersect( from, to, ref point, ref slice );
        }

        /// <summary> Tests intersection with another entity </summary>
        /// <param name="other">The entity to test</param>
        /// <returns>True if collision took place</returns>
		public override bool Intersect( Entity other, ref Vector2 projection  )
        {
            // Don't touch yourself
			if( other == this || other == null )
				return false;

			if( other is Prop && ( other as Prop ).solid != null )
				return solid.Intersect( ( other as Prop ).solid, ref projection );
			else if( solid != null )
				return solid.Intersect( other, ref projection );
			else if( other is TileMap )
				return ( other as TileMap ).Intersect( this, ref projection );
			else
				return Hax.Intersect( Position, Size, other.Position, other.Size, ref projection );
        }

        #endregion
    }
}
